/*
 *  GreedyHeuristic.cpp
 *  GRE
 *
 *  Created by Kutlak Roman on 28/08/2011.
 *  Copyright 2011 University of Aberdeen. All rights reserved.
 *
 */

#include <iostream>
#include <vector>
#include <queue>

#include "GreedyHeuristic.h"


namespace kutlak {
namespace roman {
namespace gre {
    
    // class implemented
    /////////////////////////////// PUBLIC   ///////////////////////////////////
    
#pragma mark -
#pragma mark lifecycle
    GreedyHeuristic::GreedyHeuristic(const pKnowledgeBase& kb, 
                                     const pOntology& ontology) :
    Algorithm(kb, ontology, "Greedy Heuristic") {}
    
    GreedyHeuristic::~GreedyHeuristic() = default;
    
#pragma mark -
#pragma mark operations
    //=============================  OPERATIONS  ===============================
    
    RefExp GreedyHeuristic::MakeReferringExpression(const EntityPtrT& referent, 
                                                    ContainerT distractors)
    {
        RefExp result;
        
        // check if referent is not null
        if (!referent)
            return result;
        
        // remove the referent from the set if present        
        EntityPtrEqPred pred(referent);
        auto it = std::remove_if(distractors.begin(), distractors.end(), pred);
        distractors.erase(it, distractors.end());
        
#ifdef DEBUG
        if (GH_DEBUG > 1)
            cerr << "*************: " << distractors.size() << '\n';
#endif    
        // add type first
        if (referent->Type().Value() != DEFAULT_VALUE)
        {
            result.Add(referent->Type());
            Filter(distractors, referent->Type());
        }
#ifdef DEBUG
        if (GH_DEBUG > 1)
            cerr << "*************: " << distractors.size() << '\n';
#endif
        // if the type is sufficient, return the referring expression
        if (distractors.empty()) {
            result.Prepend(Property("determiner", "definite"));
            return result;
        }
        
        typedef pair<Property, double> pairT;
        typedef std::priority_queue<pairT, std::vector<pairT>,
        PairComparator<Property, double> > pqueueT;
        
        pqueueT properties(PairComparator<Property, double>(false));
        
        for (auto prop = referent->begin(); prop != referent->end(); ++prop)
        {
            if (!IsBannedAttribute(prop->Attribute()))
            {
                Property p(*prop);
                double score = DiscriminatoryPower(distractors, p);
                pairT tmpPair = pair<Property, double>(p, score);
                properties.push(tmpPair);
            }
        }
        
        do
        {
            result.Add(properties.top().first);
            Filter(distractors, properties.top().first);
            properties.pop();
        }
        while (!distractors.empty() && !properties.empty());
        
        if (fDeterminer)
        {
            if (distractors.empty())
                result.Prepend(Property("determiner", "definite"));
            else
                result.Prepend(Property("determiner", "indefinite"));
        }
        
        return result;
    }
    
    RefExp GreedyHeuristic::MakeReferringExpression(const std::string& name)
    {
        return this->Algorithm::MRE(name);
    }
} // end namespace gre
}
}
